package org.ala.shopping_test.shopping_center.repository.shard_key;

import org.ala.shopping_test.ShardInfos;
import org.ala.tiktools.sharddb.mybatis.router.ShardInfo;
import org.ala.tiktools.sharddb.mybatis.router.shard_key_router.IShardKeyRouter;
import org.ala.tiktools.sharddb.tools.SnowIdGenerator;
import org.ala.tiktools.tools.list.Lists;
import org.ala.tiktools.tools.TimestampTools;
import org.ala.tiktools.tools.kv.KV;
import org.ala.tiktools.tools.kv.Maps;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 订单原数据分片建
 * <p>  安订单id分库
 * <p>  按下单时间分表（时序表，订单周期一般是7天，7天以后自然形成历史数据）
 *
 * @author ala
 * @date 2025-03-19 15:34
 */
public class ShoppingOrderShardKeyRouter implements IShardKeyRouter<ShoppingOrderShardKey> {


    @Override
    public Map<ShardInfo, ShoppingOrderShardKey> route(ShoppingOrderShardKey k) {
        //  如果明确指定了分库与时间戳范围，直接用
        if (k.getDb() != null || !Lists.isEmpty(k.getDbs())) {
            return routeByDB(k);
        }

        //  否则按照id路由
        return routeById(k);
    }


    /**
     *  直接指明了分库的路由方式
     *  <p>	使用直接指明的分库名，做分库
     *  <p>	使用时间范围做分表
     */
    protected Map<ShardInfo, ShoppingOrderShardKey> routeByDB(ShoppingOrderShardKey k) {
    	//	默认搜7天内的数据
        if (k.getTimestampGte() < 0 && k.getTimestampLte() < 0) {
            k.timestampLte(System.currentTimeMillis());
        } else if (k.getTimestampLte() < 0) {
            k.timestampLte(k.getTimestampGte() + 7 * TimestampTools.DAY_MS);
        } else if (k.getTimestampGte() < 0) {
            k.timestampGte(k.getTimestampLte() - 7 * TimestampTools.DAY_MS);
        }
        //  切时间范围
        List<long[]> dates = TimestampTools.cutByDay(k.getTimestampGte(), k.getTimestampLte());
        if (k.getDb() != null) {
            return dates.stream().collect(Collectors.toMap(
                    d -> ShardInfo.build(k.getDb(), TimestampTools.formatYYYYMMDD(d[1])),
                    d -> k.copy().timestampGte(d[0]).timestampLte(d[1]),
                    (o,n) -> n
            ));
        } else {
            Map<ShardInfo, ShoppingOrderShardKey> res = new HashMap<>();
            k.getDbs().forEach(db -> {
                res.putAll(dates.stream().collect(Collectors.toMap(
                        d -> ShardInfo.build(db, TimestampTools.formatYYYYMMDD(d[1])),
                        d -> k.copy().db(db).dbs((List)null).timestampGte(d[0]).timestampLte(d[1]),
                        (o,n) -> n)));
            });
            return res;
        }
    }


    protected SnowIdGenerator orderIdGenerator = SnowIdGenerator.build(1);
    /**
     *  按照id路由
     *  <p>	根据id做分库
     *  <p>	根据id上的时间戳做分表（id是雪花id，前42位可以直接拿到下单时间戳）
     */
    protected Map<ShardInfo, ShoppingOrderShardKey> routeById(ShoppingOrderShardKey k) {
    	//	如果指明了具体的原始单id，直接根据原始单id路由到库。再从id上拿时间戳路由到表
        if (k.getId() >= 0) {
            String db = ShardInfos.DB_SHOPPING_CENTER[(int)(k.getId() % ShardInfos.DB_SHOPPING_CENTER.length)];
            String table = TimestampTools.formatYYYYMMDD(k.getTimestamp());
            return Maps.build(KV.build(
                    ShardInfo.build(db, table),
                    k
            ));
        }	
        //	如果给出了原始单id列表，id列表按照上面的逻辑分库分表
        if (!Lists.isEmpty(k.getIdIn()) && !Lists.isEmpty(k.getTimestampIdIn()) && k.getIdIn().size() == k.getTimestampIdIn().size()) {
            Map<ShardInfo, ShoppingOrderShardKey> res = new HashMap<>();
            for (int i = 0; i < k.getIdIn().size(); i++) {
                long id = k.getIdIn().get(i), timestamp = k.getTimestampIdIn().get(i);
                String db = ShardInfos.DB_SHOPPING_CENTER[(int)(id % ShardInfos.DB_SHOPPING_CENTER.length)];
                String table = TimestampTools.formatYYYYMMDD(timestamp);
                res.computeIfAbsent(ShardInfo.build(db, table), _k -> k.copy().idIn(new ArrayList<>())).idIn(id).timestampIdIn(timestamp);
            }
            return res;
        }
        return null;
    }
}
